
package com.joysuch.wwyt.mh.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.enums.DataStateTypes;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.mh.bean.MhMonitoringRealTimeListBean;
import com.joysuch.wwyt.mh.bean.MhPointValueAndSwitchStateBean;
import com.joysuch.wwyt.mh.entity.MhMonitoringPoint;
import com.joysuch.wwyt.mh.entity.MhMonitoringType;
import com.joysuch.wwyt.mh.entity.dsl.QMhMonitoringPoint;
import com.joysuch.wwyt.mh.repository.MhMonitoringPointDao;
import com.joysuch.wwyt.mh.service.MhMonitoringRealTimeService;
import com.joysuch.wwyt.mh.service.MhMonitoringTypeService;
import com.joysuch.wwyt.mh.storage.IMonitorPointDataService;
import com.joysuch.wwyt.mh.storage.MonitorPointData;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class MhMonitoringRealTimeServiceImpl implements MhMonitoringRealTimeService {

    @Autowired
    private MhMonitoringPointDao mhMonitoringPointDao;
    @Autowired
    private IMonitorPointDataService monitorPointDataService;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private MhMonitoringTypeService mhMonitoringTypeService;

    @Override
    public Page<MhMonitoringRealTimeListBean> list(Pageable pageable, String name, String pointCode,
                                                   Long monitoringTypeId,Long tenantId,String companyCode) {
        pageable = PageDataUtils.addOrderByDesc(pageable, "id");
        QMhMonitoringPoint mmp = QMhMonitoringPoint.mhMonitoringPoint;
        Predicate predicate = mmp.isNotNull();

        predicate = name == null ? predicate
                : ExpressionUtils.and(predicate,
                ExpressionUtils.or(mmp.name.like("%" + name + "%"), mmp.pointCode.like("%" + name + "%")));
        // predicate = pointCode == null ? predicate : ExpressionUtils.and(predicate, mmp.pointCode.like( "%" +
        // pointCode + "%" ));
        predicate = monitoringTypeId == null ? predicate
                : ExpressionUtils.and(predicate, mmp.mhMonitoringType.id.eq(monitoringTypeId));
        predicate = ExpressionUtils.and(predicate,
                ExpressionUtils.or(mmp.showState.eq(DataStateTypes.EFFECTIVE.getState()), mmp.showState.isNull()));

        Page<MhMonitoringPoint> all = mhMonitoringPointDao.findAll(predicate, pageable);
        List<MhMonitoringRealTimeListBean> list = new ArrayList<>();
        if (!all.isEmpty()) {
            List<Long> deptIds = all.stream().map(r -> r.getResponsibleDept()).collect(Collectors.toList());
            List<BpDepart> departs = bpDepartDao.findByIds(deptIds);
            Map<Long, BpDepart> deptMap = departs.stream().collect(Collectors.toMap(BpDepart::getId, e -> e));
            for (MhMonitoringPoint m : all) {
                MhMonitoringRealTimeListBean bean = new MhMonitoringRealTimeListBean();
                bean.setId(m.getId());
                bean.setName(m.getName());
                if (m.getMhMonitoringType() != null) {
                    bean.setMonitoringTypeId(m.getMhMonitoringType().getId());
                    bean.setMinitoringTypeName(m.getMhMonitoringType().getName());
                    bean.setUnit(m.getMhMonitoringType().getUnit());
                }
                LocalDateTime realtimeValueUpdateTime = m.getRealtimeValueUpdateTime();
                bean.setCollectTime(realtimeValueUpdateTime == null ? LocalDateTime.now() : realtimeValueUpdateTime);
                MhPointValueAndSwitchStateBean bBean = getValueAndSwitchgStateBean(m,tenantId, companyCode);
                bean.setSwitchs(bBean.getSwitchs());
                bean.setConnectState(bBean.getConnectState());
                bean.setRealtimeValue(bBean.getRealtimeValue());
                bean.setPointCode(m.getPointCode());
                bean.setLevel1Threshold(m.getLevel1Threshold());
                bean.setLevel2Threshold(m.getLevel2Threshold());
                bean.setHighValue(m.getHighValue());
                bean.setLowValue(m.getLowValue());
                bean.setPointCode(m.getPointCode());
                bean.setHighValue1(m.getHighValue1());
                bean.setHighValue2(m.getHighValue2());
                bean.setLowValue1(m.getLowValue1());
                bean.setLowValue2(m.getLowValue2());
                bean.setResponsibleDept(m.getResponsibleDept());
                if (deptMap.get(Long.valueOf(m.getResponsibleDept()))!=null) {
                    String deptName = deptMap.get(Long.valueOf(m.getResponsibleDept())).getName();
                    bean.setResponsibleDeptName(deptName);;
                }
                if (m.getMhMonitoringType() != null) {
                    bean.setUnits(mhMonitoringTypeService.getPointTypeUnits(m.getMhMonitoringType()));
                }
                list.add(bean);
            }
        }
        return new PageImpl<>(list, pageable, all.getTotalElements());
    }

    @Override
    public MhPointValueAndSwitchStateBean getValueAndSwitchgStateBean(MhMonitoringPoint m, Long tenantId,String companyCode) {
        MhPointValueAndSwitchStateBean bean = new MhPointValueAndSwitchStateBean();
        if (m.getState() != null && m.getState() == 1) {
            if (m.getSwitchs() != null) {
                if (m.getSwitchs().equals("1")) {
                    bean.setSwitchs("开");
                    bean.setRealtimeValue("1.0");
                    bean.setConnectState(1);
                }
                if (m.getSwitchs().equals("0")) {
                    bean.setSwitchs("关");
                    bean.setRealtimeValue("0.0");
                    bean.setConnectState(1);
                }
            } else {
                MonitorPointData realTimeValue = monitorPointDataService
                        .realTimeVal(tenantId, companyCode,
                                m.getPointCode())
                        .orElse(null);
                if (realTimeValue == null) {
                    bean.setConnectState(0);
                } else {
                    bean.setRealtimeValue(realTimeValue.getExValue());
                    bean.setConnectState(1);
                }
            }
        } else {
            bean.setConnectState(0);
            if (m.getSwitchs() != null) {
                bean.setSwitchs("关");
                bean.setRealtimeValue("0.0");
            }
        }

        //TODO 连锁投切等类型直接显示采集数值，暂时不做状态名称mapping
//        if (m.getMhMonitoringType() != null) {
//            if ("联锁投切".equals(m.getMhMonitoringType().getName()) || "运行状态".equals(m.getMhMonitoringType().getName())) {
//                bean.setRealtimeValue(null);
//            }
//        }
//        bean.setRealtimeValue(this.getVauleByPointsUnits(m, bean.getRealtimeValue()));
        return bean;
    }

    //数值转换
    @Override
    public String getVauleByPointsUnits(MhMonitoringPoint m, String value) {
        if (m.getMhMonitoringType() != null) {
            MhMonitoringType type = m.getMhMonitoringType();
            if (StringUtils.isNotBlank(value) && type.getDefaultType() != null && type.getDefaultType().equals("Y") && StringUtils.isNotBlank(type.getUnits())) {
                Map<String, String> map = JSON.parseObject(type.getUnits(), LinkedHashMap.class, Feature.OrderedField);
                if (map.get(value) != null) {
                    return map.get(value);
                } else {
                    if (isNum(value)) {
                        for (Map.Entry<String, String> entry : map.entrySet()) {
                            if (isNum(entry.getKey()) && Math.abs(Double.valueOf(value) - Double.valueOf(entry.getKey())) < 0.0001) {
                                return map.get(entry.getKey());
                            }
                        }
                    }
                }
            }
        }
        return value;
    }

    private boolean isNum(String str) {
        String reg = "^[0-9]+(.[0-9]+)?$";
        return str.matches(reg);
    }

}
